﻿'    DotNetIRCD - An IRC Daemon written in VB.Net
'    Copyright (C) 2012 GeorgeBush
'
'    This program is free software: you can redistribute it and/or modify
'    it under the terms of the GNU General Public License as published by
'    the Free Software Foundation, either version 2 of the License, or
'    (at your option) any later version.
'
'    This program is distributed in the hope that it will be useful,
'    but WITHOUT ANY WARRANTY; without even the implied warranty of
'    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'    GNU General Public License for more details.
'
'    You should have received a copy of the GNU General Public License
'    along with this program. If not, see <http://www.gnu.org/licenses/>.

''' <summary>
''' The main module for DotNetIRCD
''' </summary>
Public Module modMain

    ''' <summary>
    ''' Saves the Date and Time that the server started
    ''' </summary>
    Friend ServerStartUpTime As DateTime = DateTime.Now

    ''' <summary>
    ''' Storage for an instance of the ServerConfiguration Class
    ''' </summary>
    Friend ServerSettings As ServerConfiguration = Nothing

    ''' <summary>
    ''' The default name for the Server Settings XML file
    ''' </summary>
    Private pSettingsFileName As String = "ServerSettings.xml"

    ''' <summary>
    ''' Holds a list of the apps threads
    ''' </summary>
    Private pThreads As New Hashtable

    ''' <summary>
    ''' Holds the ID of the next thread to be created
    ''' </summary>
    Private pThreadCount As Integer = 0

    ''' <summary>
    ''' Holds a list of the Server objects
    ''' </summary>
    Private pServers As New Hashtable

    ''' <summary>
    ''' Indicated to the Main Application Loop that the user pressed CTRL+C
    ''' </summary>
    Private pCTRLC As Boolean = False

    ''' <summary>
    ''' The application entry point
    ''' </summary>
    Sub Main()

        'Add a handler to trap a Console Key Press so we may cancel ones we want to
        AddHandler Console.CancelKeyPress, AddressOf KeyHandler

        ' Display version information
        Console.WriteLine("DotNetIRCD Version " & My.Application.Info.Version.ToString)
        Console.WriteLine("DotNetIRCD Copyright (C) 2012 GeorgeBush")
        Console.WriteLine()

        ' Check if the user has been asked if they would like to Opt-In for the Analytics
        ' Only as once unless the user clicks cancel.
        If My.Settings.AnalyticsOptInRequested = False Then
            Dim Result As MsgBoxResult = MsgBox("DotNetIRCD would like to send Usage data to it's developers to aid further development. No personal data will be sent." & vbCrLf & vbCrLf & "Would you like to Opt-In to send Application Usage Data to the DotNetIRCD Development team?", vbYesNoCancel Or vbQuestion, "Application Usage Analytics Opt-In")
            If Result = MsgBoxResult.Yes Then
                My.Settings.AnalyticsOptIn = True
                My.Settings.AnalyticsOptInRequested = True
                My.Settings.Save()
            ElseIf Result = MsgBoxResult.No Then
                My.Settings.AnalyticsOptIn = False
                My.Settings.AnalyticsOptInRequested = True
                My.Settings.Save()
            End If
        End If

        ' Show starting message on the console
        Logging.Log(LogTypeEnum.Info, LogTargetEnum.Console, "DotNetIRCD is starting...")

#If DEBUG Then
        ' Create a default settings file
        CreateDefaultSettings()
#End If

        ' Load the configuration file
        Logging.Log(LogTypeEnum.Info, LogTargetEnum.Console, "Loading settings from " & pSettingsFileName & vbCrLf)
        ServerSettings = ServerConfiguration.Load(pSettingsFileName)

        ' Create a new IRCServer Thread for each Server Binding
        For Each Binding As BindPoint In ServerSettings.Bindings

            ' Tell the BindPoint it's Thread Number
            pThreadCount += 1
            Binding.ThreadNumber = pThreadCount

            ' Create a new Server object
            Dim tServer As New ServerBinding(Binding)

            ' Create a new Thread for the Server
            Dim tThread As New System.Threading.Thread(AddressOf tServer.StartThread)

            ' Add the objects to their respective lists
            pServers.Add(pThreadCount.ToString, tServer)
            pThreads.Add(pThreadCount.ToString, tThread)

            ' Start the thread
            tThread.Start()

        Next

        ' Wait for the threads to exit
        Do

            ' Check each thread to see if it is still alive
            For Each ThisEntry As DictionaryEntry In pThreads

                ' Retrieve the Thread object from the HashTable Entry
                Dim ThisThread As Threading.Thread = CType(ThisEntry.Value, Threading.Thread)

                ' If this thread is not alive, remove it and exit the
                ' enumeration because we just broke it
                If Not ThisThread.IsAlive Then
                    pThreads.Remove(CStr(ThisEntry.Key))
                    pServers.Remove(CStr(ThisEntry.Key))
                    Exit For
                Else

                    ' If the user has pressed CTRL+C then start a safe tear down
                    If pCTRLC Then
                        ThisThread.Abort()
                    End If

                End If

            Next

            ' If there are no threads in the list we are ready to exit
            If pThreads.Count = 0 Then Exit Do

            ' These are to help with a threading issue
            ' Not sure they work though...
            If Console.KeyAvailable Then Console.Read()
            Threading.Thread.Sleep(0)

        Loop

        ' Remove the Console Cancel Key trap
        RemoveHandler Console.CancelKeyPress, AddressOf KeyHandler

        ' Wait for a key press to end
        Threading.Thread.Sleep(1000)
        Console.ForegroundColor = ConsoleColor.Gray
        Console.Write(vbCrLf & vbCrLf & "Press any key to continue...")
        Console.ReadKey()

    End Sub

    ''' <summary>
    ''' This handles the cancelling of a CTRL+C key press
    ''' </summary>
    Private Sub KeyHandler(ByVal sender As Object, ByVal args As ConsoleCancelEventArgs)

        ' Check if the user pressed CTRL+C
        If UCase(args.SpecialKey.ToString) = "CONTROLC" Then

            ' Cancel the CTRL+C
            args.Cancel = True

            ' Signal the Serve Do Loop that CTRL+C was pressed
            pCTRLC = True

        End If

    End Sub

#If DEBUG Then

    ''' <summary>
    ''' Creates a default configuration file for the server
    ''' </summary>
    ''' <remarks>This does not exists in a Release version</remarks>
    Private Sub CreateDefaultSettings()

        Dim t As New ServerConfiguration

        t.NetworkName = "DotNetIRCDNet"
        t.ServerName = "server1.dotnetircd.org"

        t.Bindings.Add(New BindPoint("192.168.0.2", "6667"))
        t.Bindings.Add(New BindPoint("localhost", "6667"))

        t.Logger.LogFileName = "DotNetIRCD.log"
        t.Logger.LogSettings.Add(New LogSetting(LogTargetEnum.Console, LogLevelEnum.Debug))
        t.Logger.LogSettings.Add(New LogSetting(LogTargetEnum.File, LogLevelEnum.Debug))

        t.Save(pSettingsFileName)

    End Sub

#End If

End Module
